package com.csht.facelib.manager;

import android.graphics.Rect;

import com.arcsoft.facedetection.AFD_FSDKEngine;
import com.csht.cshtfacetrack.Constants;
import com.csht.cshtfacetrack.CshtFaceTrackApi;
import com.csht.cshtfacetrack.CshtFaceTrackResult;
import com.csht.facelib.api.FaceSdk;
import com.csht.facelib.callback.FaceCallBack;
import com.csht.facelib.db.User;
import com.csht.facelib.model.FaceImages;
import com.csht.facelib.utils.ImageUtil;
import com.csht.facelib.utils.NdkLoader;
import com.csht.facelib.utils.SpUtils;
import com.csht.facelib.view.FaceOverlayViews;
import com.cshtface.sdk.bean.msg;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FaceManager {

    private static FaceManager instance;
    private FaceOverlayViews mFaceView;
    private ExecutorService es = Executors.newSingleThreadExecutor();
    private ExecutorService es2 = Executors.newSingleThreadExecutor();
    private Future future;
    private Future future2;
    private int frameCount;
    private CshtFaceTrackApi cshtFaceTrackApi;

    public static FaceManager getInstance(){
        if (instance == null)
            instance = new FaceManager();
        return instance;
    }

    public void initFaceTrackSdk() {
        cshtFaceTrackApi = new CshtFaceTrackApi(FaceSdk.getInstance().getContext(), AFD_FSDKEngine.AFD_OPF_0_HIGHER_EXT, SpUtils.getFaceDistance(), 1, SpUtils.isOpenLive());
    }

    public void onDetectCheck(final byte[] nowFaceYuvData, final int width, final int height,final FaceCallBack faceCallBack){
        //每3帧检测一次
        frameCount++;
        if (frameCount % 3 != 0) {
            if (frameCount > 100000) {
                frameCount = 0;
            }
            return;
        }
        if (future != null && !future.isDone())
            return;
        future = es.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    if (cshtFaceTrackApi == null) {
                        faceCallBack.onTip(0,"FaceCheckSdk初始化失败");
                        return;
                    }
                    byte[] data;
                    if (SpUtils.getDetectDirection() == 90) {
                        if (SpUtils.isDataMirror())
                            data = NdkLoader.rotateYUVDegree90AndMirror(nowFaceYuvData,width ,height);
                        else
                            data = NdkLoader.rotateYUVDegree90(nowFaceYuvData,width ,height);
                    } else if (SpUtils.getDetectDirection() == 270) {
                        if (SpUtils.isDataMirror())
                            data = NdkLoader.rotateYUVDegree270AndMirror(nowFaceYuvData,width ,height);
                        else
                            data = NdkLoader.rotateYUVDegree270(nowFaceYuvData,width ,height);
                    } else {
                        if (SpUtils.isDataMirror())
                            data = NdkLoader.mirror(nowFaceYuvData,width,height);
                        else
                            data = nowFaceYuvData;
                    }
                    CshtFaceTrackResult cshtFaceTrackResult = cshtFaceTrackApi.detectYuvFrame(data,
                            SpUtils.getDetectDirection() == 90 || SpUtils.getDetectDirection() == 270?height:width ,
                            SpUtils.getDetectDirection() == 90 || SpUtils.getDetectDirection() == 270?width:height ,
                            2050, true);
                    List<Rect> result = cshtFaceTrackResult.getList();
                    int liveness = cshtFaceTrackResult.getLiveness();
                    if (mFaceView != null){
                        mFaceView.setFaces(result);
                        if (result.size() > 0) {
                            if (SpUtils.isOpenLive()){
                                if (liveness == Constants.LIVENESS_LIVE){
                                    onLivenessCheck(result,data,
                                            SpUtils.getDetectDirection() == 90 || SpUtils.getDetectDirection() == 270?height:width ,
                                            SpUtils.getDetectDirection() == 90 || SpUtils.getDetectDirection() == 270?width:height ,
                                            faceCallBack);
                                } else if (liveness == Constants.LIVENESS_NOT_ACTIVE){
                                    faceCallBack.onTip(-3,"活体识别未激活，请联网激活");
                                } else {
                                    faceCallBack.onTip(-6,"活体识别未通过");
                                }
                            } else {
                                if (liveness == Constants.LIVENESS_NOT_ACTIVE){
                                    onLivenessCheck(result,data,
                                            SpUtils.getDetectDirection() == 90 || SpUtils.getDetectDirection() == 270?height:width ,
                                            SpUtils.getDetectDirection() == 90 || SpUtils.getDetectDirection() == 270?width:height ,
                                            faceCallBack);
                                } else {
                                    faceCallBack.onTip(-3,"未检测到人脸");
                                }
                            }
                        } else {
                            faceCallBack.onTip(-3,"未检测到人脸");
                        }
                    } else {
                        faceCallBack.onTip(-5,"人脸框异常");
                    }
                } catch (Exception e){
                    faceCallBack.onTip(-100,"比对出错");
                    e.printStackTrace();
                }
            }
        });
    }

    private void onLivenessCheck(final List<Rect> result, final byte[] yuvData, final int width, final int height, final FaceCallBack faceCallBack) {
        if (future2 != null && !future2.isDone())
            return;
        future2 = es2.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    if (!CshtCompareUtil.getInstance().isInit()) {
                        faceCallBack.onTip(-1,"sdk初始化失败");
                        return;
                    }
                    FaceImages faceImages = ImageUtil.yuv2RgbBytes(yuvData,width ,height ,result.get(0));
                    if (faceImages == null){
                        faceCallBack.onTip(-2,"数据转换失败");
                        return;
                    }
                    final byte[] nowBmp = faceImages.getNowImage();
                    byte[] faceBmp = faceImages.getNowImageHead();
                    msg[] nowFaces = CshtCompareUtil.getInstance().getCheckFaceMSG(faceBmp,result.get(0),0);
                    if (nowFaces == null) {
                        faceCallBack.onTip(-3,"未检测到人脸");
                        return;
                    }
                    if (SpUtils.isQualityControl()){
                        if (!CshtCompareUtil.isQualityFaceData(nowFaces[0])) {
                            faceCallBack.onTip(-4,"质量检测未通过");
                            return;
                        }
                    }
                    byte[] faceFeature = CshtCompareUtil.getInstance().getFaceDataFeature(nowFaces, false);
                    final User user = CshtCompareUtil.getInstance().multithreadingGroupCompare(faceFeature);
                    if (user != null) {
                        if (user.getScore() >= SpUtils.getThreshold()) {
                            ImageUtil.saveImageByNio(nowBmp, com.csht.facelib.utils.Constants.NOW_PATH+System.currentTimeMillis()+".jpg");
                            faceCallBack.onFaceDetectCallback(user);
                        } else {
                            faceCallBack.onFaceDetectCallback(null);
                        }
                    } else {
                        faceCallBack.onFaceDetectCallback(null);
                    }
                } catch (Exception e){
                    faceCallBack.onTip(-100,"比对出错");
                    e.printStackTrace();
                }
            }
        });
    }

    public void setFaceView(FaceOverlayViews mFaceView) {
        this.mFaceView = mFaceView;
    }
}
